﻿using System;
using System.Collections.Generic;
using AutoMapper;
using CollegeSim.CourseScheduler.Domain.DTO;
using CollegeSim.CourseScheduler.Domain.Entities;
using CollegeSim.CourseScheduler.Domain.Interfaces;
using CollegeSim.CourseScheduler.Domain.Interfaces.Repositories;

namespace CollegeSim.CourseScheduler.Domain.Services
{
    // Author: Ryan Redburn
    // Project: Course Scheduler
    // Date: 2/8/2014

    public class CourseService
    {
        #region [ Fields ]

        private readonly ICourseRepository _courseRepository;

        #endregion

        #region [ Constructors ]

        // Requires an instance of ICourseRepository
        public CourseService(ICourseRepository courseRepository)
        {
            _courseRepository = courseRepository;
        }

        #endregion

        #region [ Methods ]

        /// <summary>
        /// Returns a list of all Courses.
        /// </summary>
        /// <returns>List of CourseDto.</returns>
        public List<CourseDto> GetAll()
        {
            // If invalid data is received from persistence an exception is thrown to indicate thusly

            try
            {
                var courses = Mapper.Map<List<Course>>(_courseRepository.FindAll()); // Validate data
                return Mapper.Map<List<CourseDto>>(courses);
            }
            catch (ArgumentNullException)
            {
                throw new InvalidOperationException("Invalid data may have been received from persistence.");
            }
            catch (ArgumentOutOfRangeException)
            {
                throw new InvalidOperationException("Invalid data may have been received from persistence.");
            }
        }

        /// <summary>
        /// Returns a course matching the given crn.
        /// </summary>
        /// <param name="crn">Four character string CRN</param>
        /// <returns>CourseDto</returns>
        public List<CourseDto> GetByCRN(string crn)
        {
            // Throws exception for invalid crn value
            if (String.IsNullOrWhiteSpace(crn))
                throw new ArgumentNullException("crn",
                    "crn does not accept a null or empty string as an argument.");

            // Throws an exception for a crn value != 4
            if (crn.Length != 4)
                throw new ArgumentOutOfRangeException("crn", "crn must be four characters in length.");

            // Map retrieved data to domain object for data validation
            var courses = Mapper.Map<Course>(_courseRepository.FindByCRN(crn));

            // Map data back to dto for return
            return Mapper.Map<List<CourseDto>>(courses);
        }

        /// <summary>
        /// Returns a course with a matching id.
        /// </summary>
        /// <param name="id">Integer course id</param>
        /// <returns>CourseDto</returns>
        public CourseDto GetById(int id)
        {
            // Throws exception for invaild id value
            if (id < 1)
                throw new ArgumentOutOfRangeException("id",
                    "id does not accept an integer less than one as an argument.");

            // Map retrieved data to domain object for data validation
            var course = Mapper.Map<Course>(_courseRepository.FindById(id));

            // Map data back to dto for return
            return Mapper.Map<CourseDto>(course);
        }

        /// <summary>
        /// Validates and commits a course for persistence.
        /// </summary>
        /// <param name="newCourse">Course to save.</param>
        public void CommitCourse(CourseDto newCourse)
        {
            var course = Mapper.Map<Course>(newCourse);
            _courseRepository.Insert(Mapper.Map<CourseDto>(course));

        }

        /// <summary>
        /// Validates and submits a course for updating.
        /// </summary>
        /// <param name="courseUpdate">Existing course to update</param>
        public void UpdateCourse(CourseDto courseUpdate)
        {
            var course = Mapper.Map<Course>(courseUpdate);
            _courseRepository.Update(Mapper.Map<CourseDto>(course));
        }

        /// <summary>
        /// Validates and submits a course for deletion.
        /// </summary>
        /// <param name="courseDel">Course to be deleted.</param>
        public void DeleteCourse(CourseDto courseDel)
        {
            var course = Mapper.Map<Course>(courseDel);
            _courseRepository.Delete(Mapper.Map<CourseDto>(course));
        }

        #endregion
    }
}
